/*
save the vectors from the unified SRAM buffers, so that make it to be fed along diagnals of the MACArray
matSize: row size of matrix in byte
*/
package MACArraySetUp

import chisel3._
import chisel3.util._
import MyIO._

class MACArraySetUp(matSize:Int, dataWidth:Int=8, addrWidth:Int=8) extends Module{
	val io = IO(new Bundle{
		val dataIn = Input(UInt((matSize*matSize*dataWidth).W))
		val mmu2setup = new Setup_Accu(addrWidth)
		val switch = Input(Bool())

		val nextRow = Output(Vec(matSize, SInt(dataWidth.W)))
		val switchOut = Output(Vec(matSize, Bool()))//switch signals for MACArray
		val setup2accu = Flipped(new Setup_Accu(addrWidth))
	})
	
	//val topReg = RegInit(UInt(dataWidth.W))
	val firstColumnReg = RegInit(VecInit(Seq.fill(matSize)(0.U((dataWidth).W))))//create a number of matSize registers, each registers' width is dataWidth(eg:8bits)
	//for example, matrix A is 3x3, the width of each element in A is 8bits(dataWidth), or 1byte, so the matSize is 1*3=3
	//and the firstColumnReg(0) is LSB

	//connect the dataIn to firstColumnReg
	for(i <- 0 until matSize){
		firstColumnReg(i) := io.dataIn((i+1)*dataWidth-1, i*dataWidth)//connect the io.dataIn's LSB to firstColumnReg's LSB
	}

	//val lastColumn = RegInit(VecInit()) 
	val diagnonalWire = Wire(Vec(matSize, UInt(dataWidth.W)))

	//generate switch signals to matrix; the switch signals will connect to the 
	val switchReg = RegInit(VecInit(Seq.fill(matSize)(false.B)))
	// for (i <- 0 until matSize){
	// 	if(i==0){
	// 		switchReg(i) := io.switch
	// 	} else{
	// 		switchReg(i) := switchReg(i-1)
	// 	}
	// }
	for (i <- 1 until matSize){
		switchReg(i-1) := switchReg(i)
	}
	switchReg.last := io.switch


	//delay
	io.setup2accu.waddr := ShiftRegister(io.mmu2setup.waddr, matSize+1, resetData=0.U(addrWidth.W), en=true.B)//connect to accumulators' waddr
	io.setup2accu.wen := ShiftRegister(io.mmu2setup.wen, matSize+1, resetData=false.B, en=true.B)   //connect to accumulators' we
	io.setup2accu.wclear := ShiftRegister(io.mmu2setup.wclear, matSize+1, resetData=false.B, en=true.B)//conncet to accumulators' wclear
	io.setup2accu.lastvec := ShiftRegister(io.mmu2setup.lastvec, matSize, resetData=false.B, en=true.B)//doneOut delay is matSize not matSize + 1//connect to accumulators' lastvec

	io.switchOut := switchReg


	//generate buffers in a diagonal pattern
	for(i <- 0 until matSize){//row
		//diagnonalWire(i) := ShiftRegister(firstColumnReg(i), i)//the delay is greater when the index i is biger
		diagnonalWire(matSize-1-i) := ShiftRegister(firstColumnReg(i), i)//the delay of the MSB is 0 and the delay of LSB is matSize-1
	}
	for(i <- 0 until matSize){
		io.nextRow(i) := diagnonalWire(i).asSInt//reinterpret UInt to SInt
	}

}

object SetupMain extends App {
  println("Generating the MACArraySetUp hardware")
  emitVerilog(new MACArraySetUp(3,8), Array("--target-dir", "generated"))
}
